package edu.cmu.vlis.datamining.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Properties;
import java.util.Random;
import java.util.Set;

import org.jgrapht.alg.NeighborIndex;
import org.jgrapht.graph.Multigraph;

//import weka.classifiers.Evaluation;
//import weka.classifiers.functions.SMO;
//import weka.core.Instances;

import edu.cmu.vlis.datamining.tools.DatasetCreator;
import edu.cmu.vlis.datamining.utils.IOUtils;
import edu.cmu.vlis.datamining.utils.NodePair;
import edu.cmu.vlis.datamining.utils.ParserBlogBlog;
import edu.cmu.vlis.datamining.utils.TestGraphParser;

public class Main {

    public static void main(String[] args) {

        long curTime = System.currentTimeMillis();
	loadProperties(args[0]);
        IOUtils utils = new IOUtils();
        Multigraph<Vertex, Edge> trainingGraph;
        Multigraph<Vertex, Edge> testGraph;
        Map<String,Vertex> trgGraphVertexMap;
        
        System.out.println("Attempting to create Training Graph");
        File trainingGraphFile = new File(System.getProperty("trainingGraphBinFile"));
        File newEdgesInFile = new File(System.getProperty("newEdgesFile"));
        File trgVertexFile = new File(System.getProperty("trgVertexFile"));
        File testVerticesFile = new File(System.getProperty("testVerticesFile"));

        if(trainingGraphFile.exists() && trgVertexFile.exists()){
            trainingGraph = (Multigraph<Vertex, Edge>)utils.deserialzeObjFrom(trainingGraphFile);
            trgGraphVertexMap = (HashMap<String, Vertex>)utils.deserialzeObjFrom(trgVertexFile);
        }

        else{
            ParserBlogBlog parser = new ParserBlogBlog();
            parser.parse(new File(System.getProperty("trainingDataDir")));
            parser.printStats();
            trainingGraph =  parser.getGraph();
            trgGraphVertexMap = parser.getVertexMap();

            utils.serailizeObj(trainingGraph, trainingGraphFile); // Serialize for future use.
            utils.serailizeObj(trgGraphVertexMap, trgVertexFile);
        }

        System.out.println("Training Graph Created!");
        System.out.println("Starting parsing of test files..");
        
        Set<NodePair> newEdges;
        Set<Vertex> testVertices;
        if(newEdgesInFile.exists() && testVerticesFile.exists()){
            newEdges = (Set<NodePair>)utils.deserialzeObjFrom(newEdgesInFile);
            testVertices = (Set<Vertex>)utils.deserialzeObjFrom(testVerticesFile);
        }
        
        else{
            TestGraphParser testGraphParser = new TestGraphParser(trgGraphVertexMap,trainingGraph);
            newEdges = testGraphParser.getNewEdges(new File(System.getProperty("testDataDir")));
            testVertices = testGraphParser.getVerticesToItr(); 
            utils.serailizeObj(newEdges, newEdgesInFile);
            utils.serailizeObj(testVertices, testVerticesFile);
            
        } 
        System.out.println("New edges to predict: "+ newEdges.size());
        System.out.println("Vertices to iterate: "+ testVertices.size());
        
        GraphPostProcessor postProcessedGraph = new GraphPostProcessor(trainingGraph);
        NeighborIndex<Vertex, Edge> neighborIndex = postProcessedGraph.getNeighborIndex();
        System.out.println("Neighbor Index Created !");
        trainingGraph = postProcessedGraph.removeVerticesWithNoEdges();
        System.out.println("Isolated vertices removed.");
        
        List<PriorityQueue<NodePair>> predictedEdges = new FeatureExtractor().computeFeatures(trainingGraph,testVertices,neighborIndex,2*newEdges.size());
        System.out.println("All features are computed.");
        utils.serailizeObj(predictedEdges, new File(System.getProperty("predictedEdges")));
        
        Set<NodePair> allPredictedEdges = new HashSet<NodePair>();
        for(int i=0; i < 4; i++){
            Set<NodePair> predicted = new HashSet<NodePair>(Arrays.asList(predictedEdges.get(i).toArray(new NodePair[0])));
            allPredictedEdges.addAll(new HashSet<NodePair>(predicted));
            predicted.retainAll(newEdges);
            System.out.println("Correctly predicted for feature "+i+ "\t"+predicted.size());
        }
        allPredictedEdges.retainAll(newEdges);
        System.out.println("Correctly predicted after combining : "+ allPredictedEdges.size());

        for(NodePair np : allPredictedEdges){
            for(int i=0; i<4;i++ )
                System.out.println(np.getFeatureValOf(i)+"\t");
            System.out.println();

        }
        System.out.println("Total time in hours: "+ ((System.currentTimeMillis()-curTime)/(1000*60*60)));

//
//        utils.serailizeGraph(trainingGraph, new File(System.getProperty("graphWithFeatures")));
//        System.out.println("Starting classification task!");
       // doClassification(trainingGraph, testGraph, testVertexMap);

    }
    
    // using supervised machine learning approach seems infeasible.

//    private static void doClassification(Multigraph<Vertex, Edge> trainingGraph,
//                      Multigraph<Vertex, Edge> testGraph, Map<String,Vertex> testVertexMap){
//        
//        DatasetCreator creator = new DatasetCreator(trainingGraph);
//        Instances dataset = creator.prepareDataset(testGraph, testVertexMap);
//        
//        try {
//            Evaluation eval = new Evaluation(dataset);
//            eval.crossValidateModel(new SMO(), dataset, 10, new Random(1));
//            System.out.println("Class Details "+eval.toClassDetailsString());
//            System.out.println("Matrix String "+eval.toMatrixString());
//            System.out.println("Summary Classification "+eval.toSummaryString());
//
//        } catch (Exception e1) {
//            e1.printStackTrace();
//        }
//
//
//    }


    private static void loadProperties(String propFile){
        Properties props = new Properties();
        try {
            props.load(new FileInputStream(propFile));
            System.getProperties().putAll(props);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
